package a

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"strings"
	"time"

	"github.com/pkg/errors"
	"gorm.io/datatypes"
)

func A存json(data []any, 元件s []*S元件) (err error) {
	for i, 元件 := range 元件s {
		json文件名 := 元件.A名称 + ".json"
		filePath := filepath.Join(A元件cfg文件夹, json文件名)
		file, err := os.Create(filePath)
		if err != nil {
			return fmt.Errorf("创建 JSON 文件时出错: %w", err)
		}
		defer file.Close()
		// bytes, _ := json.Marshal(data[i])
		bytes, err := json.MarshalIndent(data[i], "", "    ")
		if err != nil {
			// 捕获序列化错误
			return fmt.Errorf("JSON 序列化失败: %w", err)
		}
		_, err = file.Write(bytes)
		if err != nil {
			return fmt.Errorf("写入 JSON 文件时出错: %w", err)
		}
	}
	return
}

func A存json_单个废(bytes []byte) (err error) {
	filePath := filepath.Join(A元件cfg文件夹, "开发.json")
	file, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("创建 JSON 文件时出错: %w", err)
	}
	defer file.Close()
	_, err = file.Write(bytes)
	if err != nil {
		return fmt.Errorf("写入 JSON 文件时出错: %w", err)
	}
	return
}

// func A成元件s7() (err error) {
// 	A予元件_基础部分(元件)
// 	A成元件文件(元件)
// 	for _, 元件 := range 元件.A子元件s {
// 		A成元件文件(元件, 元件)
// 	}
// 	return
// }

func A成元件s7(元件s []*S元件) (err error) {
	文件夹 := filepath.Join(A元件代码文件夹)
	A成模板文件(文件夹, "aa元件集手动部分.go.tpl", "aa元件集手动部分", 元件s)

	for _, 元件 := range 元件s {
		A元件初始化(nil, 元件)
	}
	A予元件_基础部分(元件s)

	for _, 元件 := range 元件s {
		A成元件s7_单个(nil, 元件)
	}
	return
}

func A成元件s7_单个(父元件 *S元件, 元件 *S元件) {
	// // A予元件_基础部分(元件)
	// A成元件文件(元件)
	// for _, 元件 := range 元件.A子元件s {
	// 	A成元件文件(元件, 元件)
	// }
	// return
	if 元件.A字段组 == nil {
		A成容器元件文件(元件)
	} else {
		A成元件文件(元件, 元件)
	}

	for _, 子元件 := range 元件.A子元件s {
		A成元件s7_单个(元件, 子元件)
	}
}

func A成元件给前端_从数据库() map[string]any {
	// 元件结构体 := A元件集["开发"].A元件s[0]
	// models, _ := 元件结构体.Aservice.A查_加载所有关联项()

	// 元件集 := make(map[string]any)
	// 元件集["models"] = models
	// // for key, value := range A元件集 {
	// // 	元件集[key] = value
	// // }
	// // for key, value := range A元件集 {
	// // 	元件集[key] = value
	// // }
	// return 元件集

	元件集 := make(map[string]any)
	元件集["元件集"] = A元件集
	元件集["字段集"] = A字段集
	return 元件集
}

func A成元件给前端(元件名s []string) map[string]any {
	// 直接把全局 A元件集 给前端的话 json.Marshal 可能会因为 包含 函数字段而 转换报错?
	// struct标签里面 json:- 就解决了😓
	元件集 := make(map[string]any)
	元件集["元件集"] = A元件集
	元件集["字段集"] = A字段集
	// for key, value := range A元件集 {
	// 	元件集[key] = value
	// }
	// for key, value := range A元件集 {
	// 	元件集[key] = value
	// }
	return 元件集
}

func A取元件() *S元件 {
	元件 := &S元件{}
	jsonDataBytes := A取json("老鱼商店.json")
	json.Unmarshal(jsonDataBytes, 元件)
	return 元件
}

func A予元件_开发json(json文件 string) *S元件 {
	// 开发这个元件，只能是从json构建 才方便用gorm的关联查询，如果直接查数据库，难以构成父子结构体
	元件 := &S元件{}
	jsonDataBytes := A取json(json文件)
	json.Unmarshal(jsonDataBytes, 元件)
	A递归予元件_基础部分(元件)
	return 元件
}

func A取元件s_从数据库(元件 *S元件) []*S元件 {
	// 下面的元件是指的 aa\dev\chajian\元件.go
	// 元件 := 元件.A子元件s[0]
	service := Sservice{}
	service.A元件 = 元件
	元件.Aservice = &service

	models, _ := 元件.Aservice.A查_加载所有关联项()
	jsonDataBytes2, _ := json.Marshal(models)

	元件s := []*S元件{}
	_ = json.Unmarshal(jsonDataBytes2, &元件s)
	return 元件s
}

// 同时登记元件集，后面注册元件时，元件之间可能会相互引用
func A取元件s(元件名s []string) []*S元件 {
	// filenames := []string{"老鱼商店.json"}
	// filenames = append(filenames, "项目管理.json")
	元件s := []*S元件{}
	for _, 元件名 := range 元件名s {
		元件 := &S元件{}
		jsonDataBytes := A取json(元件名)
		json.Unmarshal(jsonDataBytes, 元件)
		元件s = append(元件s, 元件)
		A元件集[元件.A名称] = 元件
		A元件初始化(nil, 元件)
		// for _, 元件 := range 元件.A子元件s {
		// 	元件.A元件名 = 元件.A名称
		// 	A成表名(元件)
		// 	元件.A自动挡hook = &S元件自动挡hook{}
		// 	A元件集[A成id(元件.A名称, 元件.A名称)] = 元件
		// }
	}
	return 元件s
}

func A元件初始化(父元件 *S元件, 元件 *S元件) {
	// A成包路径(父元件, 元件)
	// if 父元件 != nil {
	// 	元件.A父id = 父元件.Aid
	// }
	A予id(父元件, 元件)
	A元件集[元件.Aid] = 元件

	// 末级组件才需要👇
	if 元件.A字段组 != nil {
		A成表名(元件)
		A成model名_go(元件)
		元件.A自动挡hook = &S元件自动挡hook{}
	}

	for _, 子元件 := range 元件.A子元件s {
		A元件初始化(元件, 子元件)
	}

}

func A成容器元件文件(元件 *S元件) {
	文件夹 := A成文件夹名(元件)
	A成模板文件(文件夹, "容器元件.go.tpl", 元件.A名称, 元件)
}

func A成文件夹名(元件 *S元件) (文件夹 string) {
	路径组 := strings.Split(元件.A英文id, "/")
	路径组 = append([]string{A元件代码文件夹}, 路径组...)
	文件夹 = filepath.Join(路径组...)
	return
}

func A成元件文件(父元件 *S元件, 元件 *S元件) {
	// 元件.A元件名 = 元件.A名称
	文件夹 := A成文件夹名(元件)
	A成模板文件(文件夹, "元件.go.tpl", 元件.A名称, 元件)

	if 元件.A有自动挡hook {
		A成模板文件(文件夹, "自动挡hook.go.tpl", 元件.A名称+"自动挡hook", 元件)
	}
	if 元件.A有手动挡 {
		A成模板文件(文件夹, "手动挡.go.tpl", 元件.A名称+"手动挡", 元件)
	}

	// 文件夹 = filepath.Join(A元件model文件夹, 元件.A元件名)
	文件夹 = filepath.Join(A元件model文件夹)
	A成模板文件(文件夹, "model.go.tpl", 元件.Amodel名, 元件)
}

func A含json否(str string) bool {
	re := regexp.MustCompile(`arr|图片|富文本`)
	return re.MatchString(str)
}

func A成模板文件(文件夹 string, 模板名 string, 文件名 string, 元件或元件s any) {
	fmt.Printf("元件或元件s信息: %+v\n", 元件或元件s)
	// A字段组 := A取字段值(元件或元件s, "A字段组")
	// fmt.Printf("A字段组 👉 %+v\n", A字段组)

	os.MkdirAll(文件夹, 0755)

	文件全名 := filepath.Join(文件夹, fmt.Sprintf("%s.go", 文件名))

	// 文件已经存在👇
	if _, err := os.Stat(文件全名); err == nil {
		if A含其中之一(文件名, "hook|手动挡", false) {
			return
		}
		// 获取当前时间毫秒数
		// now := time.Now().UnixNano() / 1e6
		now := time.Now().Format("2006-01-02 15-04.000")
		backupDir := filepath.Join(fmt.Sprintf("删除保留/%s", now), A元件代码文件夹)
		os.MkdirAll(backupDir, 0755)

		relPath, _ := filepath.Rel(A元件代码文件夹, 文件全名)
		backupFilePath := filepath.Join(backupDir, relPath)
		// 创建备份文件所在目录
		备份目录 := filepath.Dir(backupFilePath)
		os.MkdirAll(备份目录, 0755)
		// 转移文件
		os.Rename(文件全名, backupFilePath)
	} else {
		// fmt.Printf("FileInfo 👉 %+v\n", FileInfo)
		fmt.Printf("err 👉 %+v\n", err)
	}
	outputFile, _ := os.Create(文件全名)

	tplPath := filepath.Join("a", "template", 模板名)
	tplContent, _ := os.ReadFile(tplPath)
	funcMap := template.FuncMap{
		"解json": 解json,
	}
	// tpl, err := template.New("example").Funcs(funcMap).Parse(tplContent)
	tpl, _ := template.New("元件或元件s").Option("missingkey=zero").Funcs(funcMap).Parse(string(tplContent))
	defer outputFile.Close()
	err := tpl.Execute(outputFile, 元件或元件s)
	if err != nil {
		fmt.Printf("err 👉 %+v\n", err)
	}
}

// 将 datatypes.JSON 转换为 Go 语言中 datatypes.JSON 字面量格式的字符串
func 解json(data datatypes.JSON) map[string]any {
	var result map[string]any
	err := json.Unmarshal([]byte(data), &result)
	if err != nil {
		return nil
	}
	return result
}

// func A成元件(json文件 string, 元件 *S元件) (元件 *S元件) {
// 	jsonDataBytes := A取json(json文件)
// 	元件 = &S元件{}
// 	err := json.Unmarshal(jsonDataBytes, 元件)
// 	if err != nil {
// 		_ = fmt.Errorf("解析 JSON 文件失败: %w", err)
// 	}
// 	model := A成model(元件, 元件)
// 	元件.Amodel = model
// 	return
// }

func A取json(relativePath string) (jsonDataBytes []byte) {
	jsonFilePath := filepath.Join(A元件cfg文件夹, relativePath)
	jsonFile, err := os.Open(jsonFilePath)
	// fmt.Printf("jsonFilePath 👉 %+v\n", jsonFilePath)
	APrintf("jsonFilePath 👉 %+v", jsonFilePath)
	fmt.Printf("err 👉 %+v\n", err)
	if err != nil {
		// return fmt.Errorf("打开 JSON 文件失败: %w", err)
		errors.Wrapf(err, "[jsonFilePath:%s] 出错!", jsonFilePath)
	}
	defer jsonFile.Close()

	// 读取文件内容
	jsonDataBytes, err = io.ReadAll(jsonFile)
	if err != nil {
		_ = fmt.Errorf("读取 JSON 文件内容失败: %w", err)
	}
	return
}

// 用反射动态生成的model不符合要求？字段名显示为 internal/abi.A名称 {Bytes: *3} 不符合gorm首字母大写的要求？
func A成model_反射方式(父元件 *S元件, 元件 *S元件) any {
	字段s := 元件.A字段组
	fields := make([]reflect.StructField, 0, len(字段s))

	for _, 字段 := range 字段s {
		var 字段类型 reflect.Type
		switch 字段.A类型 {
		case "string":
			字段类型 = reflect.TypeOf("")
		case "int":
			字段类型 = reflect.TypeOf(0)
		case "float64":
			字段类型 = reflect.TypeOf(0.0)
		// 可以根据需要添加更多类型
		default:
			fmt.Printf("不支持的类型: %s\n", 字段.A类型)
			continue
		}

		field := reflect.StructField{
			// Name:    "A" + 字段.A名称,
			Name:    字段.A名称go,
			Type:    字段类型,
			Tag:     reflect.StructTag(fmt.Sprintf(`json:"%s" gorm:"column:%s;备注:;"`, 字段.A名称, 字段.A名称)),
			PkgPath: "",
		}
		fields = append(fields, field)
	}

	structType := reflect.StructOf(fields)
	instance := reflect.New(structType).Elem()
	kk := instance.Interface()
	return kk
}
